import { Register } from "../register/Register";
import { Base } from "../core/Base";
import { any, has } from "../core/logic";
import { Component, ComponentType } from "../component/Component";
import { Destroy } from "../component/index";
/**
 * 实体类，所有的业务组件的载体。
 * @class
 * @memberof w
 */
class Entity extends Base {
    /**
     * @constructor
     * @param {String} opts.group 
     * 【可选，缺省值:"default"】实体对象的组名，相同的分组会打包在一起，合理的分组能有效提高引擎的性能表现。具体逻辑:频繁更新的数据尽可能的进行分组，减少更新的范围，因为组内实体的更新会触发整个组的更新。
     * @param {Boolean} opts.disablePick 
     * 【可选，缺省值:false】禁止拾取,如果设为true,即使{@link w.Engine#enablePick}。
     */
    constructor(opts = {}) {
        super(opts);
        this._type = "Entity";
        this._visibility = true;
        this._group = any(opts.group, "default");
        this._parent = null;
        this._children = [];
        this._components = [];
        this.disablePick = any(opts.disablePick, false);
        Register.instance.entityManager.add(this);
    }
    /**
     * @property  {String} type 
     * 【只读】实体对象的类型。
     */
    get type() {
        return this._type;
    }
    get group() {
        return this._group;
    }
    /**
     * @property  {String} group 
     * 【读写】实体对象的组名，相同的分组会打包在一起，合理的分组能有效提高引擎的性能表现。具体逻辑:频繁更新的数据尽可能的进行分组，减少更新的范围，因为组内实体的更新会触发整个组的更新。
     */
    set group(v) {
        this._group = v;
        return this;
    }
    get parent() {
        return this._parent;
    }
    /**
     * @property  {String} parent 
     * 【读写】实体对象的组名，相同的分组会打包在一起，合理的分组能有效提高引擎的性能表现。具体逻辑:频繁更新的数据尽可能的进行分组，减少更新的范围，因为组内实体的更新会触发整个组的更新。
     */
    set parent(v) {
        this._parent = v;
        return this;
    }
    /**
     * @property  {Array<String>} children 
     * 【只读】实体对象的孩子。
     */
    get children() {
        return this._children;
    }
    /**
     * @property  {Array} components 
     * 【只读】实体对象所具有的业务组件。
     */
    get components() {
        return this._components;
    }
    get visibility() {
        return this._visibility;
    }
    /**
     * @property  {Boolean} visibility 
     * 【读写】实体对象可见性。
     */
    set visibility(v) {
        if (v !== this.visibility) {
            this._visibility = v;
            if (this.mesh) {
                this.mesh.visibility = v
            }
        }
    }
    /**
     * @property  {Trans} trans 
     * 【只读】实体对象的Trans组件,如没有则返回undefine。
     */
    get trans() {
        return this.getComponent(ComponentType.Trans);
    }
    /**
    * @property  {Mesh} mesh 
    * 【只读】实体对象的Mesh组件,如没有则返回undefine。
    */
    get mesh() {
        return this.getComponent(ComponentType.Mesh);
    }
    get script(){
        return this.getComponent(ComponentType.Script);
    }
    /**
     * @property  {Pick} pick 
     * 【只读】实体对象的Pick组件,如没有则返回undefine。
     */
    get pick() {
        return this.getComponent(ComponentType.Pick);
    }
    /**
     * @property  {Plot} plot 
     * 【只读】实体对象的Plot组件,如没有则返回undefine。
     */
    get plot() {
        return this.getComponent(ComponentType.Plot);
    }
    /**
     * @property  {HemisLight} hemisLight 
     * 【只读】实体对象的HemisLight组件,如没有则返回undefine。
     */
    get hemisLight() {
        return this.getComponent(ComponentType.HemisLight);
    }
    /**
     * @property  {AmbientLight} ambientLight 
     * 【只读】实体对象的AmbientLight组件,如没有则返回undefine。
     */
    get ambientLight() {
        return this.getComponent(ComponentType.AmbientLight);
    }
    /**
     * @property  {PostProcessing} postProcessing 
     * 【只读】实体对象的PostProcessing组件,如没有则返回undefine。
     */
    get postProcessing() {
        return this.getComponent(ComponentType.PostProcessing);
    }
    /**
     * @property  {PostProcessing} punctualLight 
     * 【只读】实体对象的PunctualLight组件,如没有则返回undefine。
     */
    get punctualLight() {
        return this.getComponent(ComponentType.PunctualLight);
    }
    /**
     * @property  {Pick} Pick 
     * 【只读】实体对象的Pick组件,如没有则返回undefine。
     */
    get pick() {
        return this.getComponent(ComponentType.Pick);
    }
    /**
     * @property  {Orbit} orbit 
     * 【只读】实体对象的Orbit组件,如没有则返回undefine。
     */
    get orbit() {
        return this.getComponent(ComponentType.Orbit);
    }
    /**
     * @property  {Transform} transform 
     * 【只读】实体对象的Transform组件,如没有则返回undefine。
     */
    get transform(){
        return this.getComponent(ComponentType.Transform);
    }
    /**
     * 递归设置实体的可见性。
     * @method
     * @param {Boolean} v 参数为true或false。
     */
    setVisibility(v) {
        this.visibility = v;
        for (let i = 0; i < this.children.length; i++) {
            let entityId = this.children[i]
            const clildEntity = Register.instance.entityManager.get(entityId);
            clildEntity.setVisibility(v);
        }
        return this;
    }
    /**
     * 添加方法，添加的对象会成为该实体children中的一项。
     * @method
     * @param {Entity} entity 
     * @param {Number} index 
     */
    add(entity, index = 999999) {
        if (entity.parent) {
            if (entity.parent !== this.id) {//重新绑定新的父节点。从老的父节点清除。
                const parent = Register.instance.entityManager.get(entity.parent);
                if (parent) {
                    const index = parent.children.indexOf(entity.id);
                    parent.children.splice(index, 1);
                }
            }
        } else {
            entity.parent = this.id;
        }
        let loc = this.children.indexOf(entity.id);
        if (loc === -1) {
            this.children.splice(Math.min(index, this.children.length), 0, entity.id);
        }
        return this;
    }
    /**
     * 从孩子中找到该id对应的实体，销毁并从孩子数组中移除。
     * @method
     * @param {String} id 要删除的孩子实体id。
     */
    remove(id, destroy = true) {
        let entity = Register.instance.entityManager.get(id);
        //删除他所有的孩子
        if (entity) {
            if (destroy) {
                entity.destroy();
            } else {
                entity.removeFromParent();
                entity.update();
            }

        }
    }
    /**
     * 移除所有的孩子实体。
     * @method
     */
    removeAll(destroy = true) {
        for (let i = this.children.length - 1; i >= 0; i--) {
            let id = this.children.pop();
            this.remove(id, destroy);
        }
    }
    /**
     * 将该实体从父实体中移除（如果有父实体）。
     * @method
     */
    removeFromParent() {
        let parent = this.getParent();
        if (parent) {
            let index = parent.children.indexOf(this.id);
            parent.children.splice(index, 1);
        }
        this.parent = null;
    }
    get(id) {
        return Register.instance.entityManager.get(id);
    }
    /**
     * 获取所有的孩子实体对象。
     * @method
     * @return {Array<Entity>} 返回所有的实体集合。
     */
    getAll() {
        let entities = [];
        for (let i = 0; i < this.children.length; i++) {
            let entity = this.get(this.children[i]);
            entities.push(entity);
        }
        return entities;
    }
    getAllRecusion() {
        let out=[];
        this._getAllRecusion(out);
        return out;
    }
    _getAllRecusion(entities){
        for (let i = 0; i < this.children.length; i++) {
            let entity = this.get(this.children[i]);
            entities.push(entity);
            entity.getAllRecusion(entities);

        }
    }
    getAllInstance(){
        let out=[];
        if(this.trans.hash=="transinstance"){
            out.push(this);
        }
        this._getAllInstance(out);
        return out;
    }
    _getAllInstance(entities){
        for (let i = 0; i < this.children.length; i++) {
            let entity = this.get(this.children[i]);
            if(entity.trans.hash=="transinstance"){
                entities.push(entity);
            }
            entity._getAllInstance(entities);

        }
    }
    /**
     * 获取父实体对象。
     * @method
     * @return {Array<Entity>} 如果有则返回父实体，否则返回false。
     */
    getParent() {
        if (this.parent) {
            return Register.instance.entityManager.get(this.parent);
        }
        return false;
    }
    checkComponent(component) {
        if (!(component instanceof Component)) {
            throw new Error(`不是有效组件类型!`);
        }
    }
    /**
     * 添加组件
     * @param {Component} component 组件对象
     */
    addComponent(component) {
        this.checkComponent(component);
        const { type, id } = component;
        Register.instance.manager(type).add(component);//添加到组件管理类中
        component.attach(this.id);
        this.components[type] = id;//写入实体组件标识中
    }
    /**
     * 移除组件
     * @param {Component} component 组件对象
     */
    removeComponent(type) {
        let component = this.getComponent(type);
        if (component) {
            this.components[type] = undefined;
            component.deactive();
            component.detach(this.id);
            let flag = component.destroy();
            if (flag) {
                component = null;
            }
        }

    }
    /**
     * 移除全部组件
     * @param {Component} component 组件对象
     */
    removeAllComponent() {
        for (let i = this.components.length - 1; i >= 0; i--) {
            this.components[i]
            this.removeComponent(i);
        }
        this._components = null;
    }
    /**
     * 获取组件
     * @param {Number} type 组件类型。
     */
    getComponent(type) {
        const cid = this.components[type];
        if (cid) {
            return Register.instance.manager(type).get(cid);
        }
        return null;
    }
    /**
     * 获取组件是否存在
     * @param {Number} type 组件类型。
     */
    hasComponent(type) {
        return this.components[type];
    }
    /**
     * 获取所有组件
     */
    getAllComponent() {
        let components = [];
        for (let i = 0; i < this.components.length; i++) {
            if (this.components[i]) {
                components.push(this.getComponent(i));
            }

        }
        return components;
    }

    findRoot(entity) {
        if (!entity) {
            // debugger
        }
        if (!has(entity.parent)) {
            return entity;
        } else {
            let parentEntity = this.get(entity.parent);
            return this.findRoot(parentEntity);
        }
    }
    /**
     * 获取实体的根节点。
     */
    getRoot() {
        return this.findRoot(this);
    }
    /**
     * 销毁实体
     */
    destroy(task = false,isTop) {
        if (task) {
            this.addComponent(new Destroy());
        } else {
            if(isTop){
                const destroyCom = this.getComponent(ComponentType.Destroy)
                if (!destroyCom) {
                    return
                }
            }
            this.removeFromParent();//从父亲中删除
            Register.instance.entityManager.remove(this.id);//删除本身
            this.removeAllComponent();
            this.removeAll();//删除所有孩子
            super.destroy();
            this._group = null;
         
        }


    }
    update() {//再实体添加到group中调用。
        //本身更新
        const coms = this.getAllComponent();
        for (let i = 0; i < coms.length; i++) {
            coms[i].update();
        }
        //孩子更新
        const children = this.getAll();
        for (let i = 0; i < children.length; i++) {
            children[i].update();
        }
    }
}
export { Entity }